package main

import (
	"errors"
	"fmt"
)

func testThrowErr(ext ...int) {
	for _, e := range ext {
		fmt.Println(e)
		throwErr()
		continue
	}
}

func main() {
	testFunTryCatch()
}

// 单个函数的方式实现tryCath
func testFunTryCatch() {
	TryCatchFinally(func() {
		throwErr()
	}, func(err error) {
		fmt.Printf("%v\n", err)
	}, func() {
		fmt.Println("finally")
	})
}

func TryCatch(try func(), catch func(error)) {
	defer func() {
		if err := recover(); err != nil {
			switch err2 := err.(type) {
			case error:
				catch(err2)
			default:
				catch(errors.New(fmt.Sprintf("%v\n", err)))
			}
		}
	}()
	try()
}
func TryCatchFinally(try func(), catch func(error), finally func()) {
	defer finally()
	TryCatch(try, catch)
}

// tools
func throwErr() {
	for i := 2; i > -1; i-- {
		_ = i / i
	}
}

// 多个函数的方式实现tryCatch
func testMultiFunCatch() {
	var r int
	defer Finally(func() {
		fmt.Println("finally")
	})

	defer Catch(func(err error) {
		fmt.Printf("%v\n", err)
	})

	throwErr()
	fmt.Println(r)
}

func Finally(fun func()) {
	fun()
}

func Catch(fun func(error)) {
	if err := recover(); err != nil {
		switch err2 := err.(type) {
		case error:
			fun(err2)
		default:
			fun(errors.New(fmt.Sprintf("%v\n", err)))
		}
	}
}

// ----  利用结构体实现的TryCatch功能-----
func testStructTryCatch() {
	var r int
	defer func() {
		fmt.Println("finally", r)
	}()

	Try(func() {
		for i := 2; i > -1; i-- {
			r = i / i
		}
	}).Catch(func(err error) {
		fmt.Printf("error:%v\n", err)
	})
}

type TryCatchStruct struct {
	try func()
}

func Try(fun func()) *TryCatchStruct {
	return &TryCatchStruct{
		try: fun,
	}
}

func (tc *TryCatchStruct) Catch(fun func(error)) {
	defer func() {
		if err := recover(); err != nil {
			switch err2 := err.(type) {
			case error:
				fun(err2)
			default:
				fun(errors.New(fmt.Sprintf("%v\n", err)))
			}
		}
	}()
	tc.try()
}
